#include "Parser.h"
#include "util/StringUtils.h"

namespace parser {
Parser::Parser(Rule* rule, std::string filename) {
	this->file = NULL;
	this->rule = rule;
	this->commentIndicator = "#";
	this->setFileName(filename);
}

Parser::~Parser() {
	if (this->file != NULL) {
		delete this->file;
	}
}

Parser* Parser::setFileName(std::string fileName) {
	if (this->file != NULL) {
		delete this->file;
	}
	this->file = new util::File(fileName);
	return this;
}

ParsedData* Parser::processNextLine() throw (util::IOException, InvalidDataException) {
	std::string line;
	if (!(this->file->isOpen())) {
		this->file->openFileReadOnly();
	}
	line = this->file->readLine();
	//Saco el enter que lee del final el readline
	char lineSeparator = '\r';
	if (line[line.size() - 1] == lineSeparator) {
		line = line.substr(0, line.length() - 1);
	}
	std::string::iterator it;
	std::string buff;

	// Si la linea es un comentario, o es una linea vacia se lee una nueva linea
	while (!(line.substr(0, this->commentIndicator.size()).compare(this->commentIndicator))
			|| (line.size()==0)) {
		// caso especial: si la ultima linea es comentario o linea vacia, no se
		// debe leer mas lineas del archivo (porque es la ultima!!)
		if (this->file->endOfFile())
			return this->rule->getParsedData(true);

		line = this->file->readLine();
	}
	try {
		for (it = line.begin(); it < line.end(); it++) {
			char c = *it;
			if (c != this->rule->getDataSeparator()) {
				buff += c;
			} else {
				this->addValueToRule(buff);
				buff = "";
			}
		}
		if (buff != "") {
			this->addValueToRule(buff);
		}
	} catch (util::Exception &e) {
		this->rule->discardCurrentParsedData();
		throw ;
	}
	return this->rule->getParsedData(true);
}

bool Parser::noMoreDataInFile() throw (util::IOException) {
	if (this->file != NULL) {
		return this->file->endOfFile();
	} else {
		throw(util::IOException("No se puede acceder al archivo \"" + this->file->getFileName() + "\"."));
	}
}

std::string Parser::getFileName() {
	return this->file->getFileName();
}

std::string Parser::getStrLineNumber() {
	return util::intToString(this->file->getCurrentLineNumber());
}

void Parser::addValueToRule(std::string value) throw (InvalidDataException) {
	util::trim(value);
	this->rule->addValue(value);
}

void Parser::setCommentIndicator(std::string indicator) {
	this->commentIndicator = indicator;
}

}
